package com.chen.apply.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chen.apply.mapper.ApplyMapper;
import com.chen.apply.mapper.InvoiceMapper;
import com.chen.apply.mapper.PlanMapper;
import com.chen.apply.mapper.ReimburseMapper;
import com.chen.apply.service.ReimburseService;
import com.common.pojo.entity.*;
import com.common.pojo.req.ReimburseSubmitReqDTO;
import com.common.pojo.req.ReimburseUpdateReqDTO;
import com.common.pojo.resp.ReimburseEditRespDTO;
import com.common.pojo.resp.ReimburseManageRespDTO;
import com.common.pojo.resp.ReimburseShowRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ReimburseServiceImpl extends ServiceImpl<ReimburseMapper, Reimburse> implements ReimburseService {

    @Autowired
    private ApplyMapper applyMapper;

    @Autowired
    private PlanMapper planMapper;

    @Autowired
    private ReimburseMapper reimburseMapper;

    @Autowired
    private InvoiceMapper invoiceMapper;

    @Override
    public List<ReimburseManageRespDTO> getReimburseManageRespDTO(Integer userId) {

        // 1. 查询符合条件的申请列表
        List<Apply> applies;
        // 如果指定了用户ID，只查询该用户的数据
        applies = applyMapper.selectList(new QueryWrapper<Apply>()
                .eq("user_id", userId)
                .in("status", Apply.ADVANCE_APPROVED, Apply.REIMBURSE_REJECTED)
                .orderByDesc("create_time"));


        if (applies.isEmpty()) {
            return new ArrayList<>();
        }

        // 2. 批量获取申请ID列表
        List<Integer> applyIds = applies.stream()
                .map(Apply::getId)
                .collect(Collectors.toList());


        // 4. 批量获取每个申请的行程计划
        Map<Integer, List<Plan>> plansMap = getPlansByApplyIds(applyIds);

        // 5. 构建返回结果
        return applies.stream().map(apply -> {
            ReimburseManageRespDTO dto = new ReimburseManageRespDTO();

            BeanUtils.copyProperties(apply,dto);

            // 设置总预算
            dto.setTotalBudget(planMapper.selectTotalBudgetByApplyId(apply.getId()));

            // 设置行程计划
            dto.setPlans(plansMap.getOrDefault(apply.getId(), new ArrayList<>()));

            return dto;
        }).collect(Collectors.toList());

    }

    @Override
    public boolean submitReimburse(ReimburseSubmitReqDTO dto) {

        log.info("dto:{}",dto);
        // 1. 验证申请是否存在且状态允许报销
        Apply apply = applyMapper.selectById(dto.getApplyId());
        if (apply == null) {
            throw new RuntimeException("申请不存在");
        }

        // 检查申请状态是否允许提交报销
        if (!isStatusAllowedForReimburse(apply.getStatus())) {
            throw new RuntimeException("当前申请状态不允许提交报销");
        }

        // 2. 保存报销记录到 reimburse 表
        Reimburse reimburse = new Reimburse();
        BeanUtils.copyProperties(dto,reimburse);
        reimburse.setUpdateTime(LocalDateTime.now());
        reimburse.setCreateTime(LocalDateTime.now());
        boolean reimburseSaved = this.save(reimburse);

        if (!reimburseSaved) {
            throw new RuntimeException("保存报销记录失败");
        }

        // 3. 保存发票信息到 invoice 表
        if (dto.getInvoiceUrls() != null && !dto.getInvoiceUrls().isEmpty()) {
            boolean invoicesSaved = saveInvoices(dto.getInvoiceUrls(), reimburse.getId());
            if (!invoicesSaved) {
                throw new RuntimeException("保存发票信息失败");
            }
        }
        return true;
    }

    @Override
    public List<ReimburseShowRespDTO> getReimburseShowRespDTO(Integer applyId) {
        // 1. 获取该申请的所有行程计划
        List<Plan> plans = planMapper.selectList(new QueryWrapper<Plan>()
                .eq("apply_id", applyId)
                .orderByAsc("id"));

        if (plans.isEmpty()) {
            return new ArrayList<>();
        }

        // 2. 获取计划ID列表
        List<Integer> planIds = plans.stream()
                .map(Plan::getId)
                .collect(Collectors.toList());

        // 3. 批量获取每个计划的报销记录
        Map<Integer, List<Reimburse>> reimburseMap = getReimbursesByPlanIds(planIds);

        // 4. 批量获取报销记录的发票信息
        Map<Integer, List<Invoice>> invoiceMap = getInvoicesByReimburseIds(
                reimburseMap.values().stream()
                        .flatMap(List::stream)
                        .map(Reimburse::getId)
                        .collect(Collectors.toList())
        );


        // 6. 构建返回结果
        return plans.stream().map(plan -> {
            ReimburseShowRespDTO dto = new ReimburseShowRespDTO();

            // 设置计划基本信息
            dto.setId(plan.getId());
            dto.setApplyId(plan.getApplyId());
            dto.setType(plan.getType());
            dto.setDetail(plan.getDetail());
            dto.setBudgetAmount(plan.getBudgetAmount());
            dto.setBudgetDetail(plan.getBudgetDetail());
            dto.setOverspendReason(plan.getOverspendReason());

            // 设置该计划的总报销金额
            dto.setTotalReimburseAmount(reimburseMapper.selectTotalReimburseByPlanId(plan.getId()));

            // 设置该计划的报销明细
            List<ReimburseDetail> reimburseDetails = buildReimburseDetails(
                    reimburseMap.getOrDefault(plan.getId(), new ArrayList<>()),
                    invoiceMap
            );
            dto.setReimburseDetails(reimburseDetails);

            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public boolean deleteReimburse(Integer reimburseId) {

        LambdaQueryWrapper<Invoice> queryWrapper = new LambdaQueryWrapper<Invoice>().eq(Invoice::getReiId, reimburseId);
        invoiceMapper.delete(queryWrapper);
        boolean reimburseDeleted = this.removeById(reimburseId);
        return true;
    }

    @Override
    public ReimburseEditRespDTO getReimburseEditData(Integer reimburseId) {
        // 1. 获取报销记录基本信息
        Reimburse reimburse = this.getById(reimburseId);
        if (reimburse == null) {
            throw new RuntimeException("报销记录不存在");
        }

        // 2. 获取关联的发票信息
        List<Invoice> invoices = invoiceMapper.selectList(
                new QueryWrapper<Invoice>().eq("rei_id", reimburseId).orderByAsc("id")
        );

        ReimburseEditRespDTO dto = new ReimburseEditRespDTO();
        BeanUtils.copyProperties(reimburse,dto);
        dto.setInvoices(invoices);
        return dto;

    }

    @Override
    public boolean updateReimburse(ReimburseUpdateReqDTO updateReqDTO) {

        Reimburse reimburse = new Reimburse();
        BeanUtils.copyProperties(updateReqDTO,reimburse);

        reimburse.setUpdateTime(LocalDateTime.now());
        boolean reimburseUpdated = this.updateById(reimburse);

        if (!reimburseUpdated) {
            throw new RuntimeException("更新报销记录失败");
        }
        log.info("更新：{}",updateReqDTO.getInvoices());
        // 3. 更新发票信息
        if (updateReqDTO.getInvoices() != null) {
            boolean invoicesUpdated = updateInvoices(reimburse.getId(), updateReqDTO.getInvoices());
            if (!invoicesUpdated) {
                throw new RuntimeException("更新发票信息失败");
            }
        }

        return true;
    }

    @Override
    public boolean changeReimburseState(Integer id) {
        LambdaUpdateWrapper<Apply> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Apply::getId, id)
                .set(Apply::getStatus, 6);
        applyMapper.update(null, updateWrapper);

        return true;
    }

    private boolean updateInvoices(Integer reimburseId, List<Invoice> newInvoices) {
        log.info("id:{},invocies:{}",reimburseId,newInvoices);
        // 1. 删除原有的发票记录
        int deleted = invoiceMapper.delete(new QueryWrapper<Invoice>().eq("rei_id", reimburseId));

        // 2. 插入新的发票记录
        if (!newInvoices.isEmpty()) {
            for (Invoice invoice : newInvoices) {
                invoice.setId(null); // 确保ID为空，让数据库自增
                invoice.setReiId(reimburseId); // 设置关联的报销记录ID
                int result = invoiceMapper.insert(invoice);
                if (result <= 0) {
                    return false;
                }
            }
        }

        return true;
    }


    /**
     * 批量获取申请的行程计划
     */
    private Map<Integer, List<Plan>> getPlansByApplyIds(List<Integer> applyIds) {
        List<Plan> allPlans = planMapper.selectList(new QueryWrapper<Plan>()
                .in("apply_id", applyIds)
                .orderByAsc("apply_id", "id"));

        Map<Integer, List<Plan>> plansMap = new HashMap<>();
        for (Plan plan : allPlans) {
            plansMap.computeIfAbsent(plan.getApplyId(), k -> new ArrayList<>()).add(plan);
        }

        return plansMap;
    }

    /**
     * 检查申请状态是否允许提交报销
     */
    private boolean isStatusAllowedForReimburse(Integer status) {
        // 允许提交报销的状态：预支付款审核通过、报销申请未通过
        return status == Apply.ADVANCE_APPROVED ||
                status == Apply.REIMBURSE_REJECTED;
    }


    /**
     * 保存发票URL列表
     */
    private boolean saveInvoices(List<String> invoiceUrls, Integer reimburseId) {
        for (String invoiceUrl : invoiceUrls) {
            Invoice invoice = Invoice.builder()
                    .reiId(reimburseId)
                    .invoiceImg(invoiceUrl)
                    .build();

            int result = invoiceMapper.insert(invoice);
            if (result <= 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * 批量获取每个计划的报销记录
     */
    private Map<Integer, List<Reimburse>> getReimbursesByPlanIds(List<Integer> planIds) {
        List<Reimburse> reimburses = this.list(new QueryWrapper<Reimburse>()
                .in("plan_id", planIds)
                .orderByAsc("plan_id", "create_time"));

        Map<Integer, List<Reimburse>> reimburseMap = new HashMap<>();
        for (Reimburse reimburse : reimburses) {
            reimburseMap.computeIfAbsent(reimburse.getPlanId(), k -> new ArrayList<>())
                    .add(reimburse);
        }

        return reimburseMap;
    }

    /**
     * 批量获取报销记录的发票信息
     */
    private Map<Integer, List<Invoice>> getInvoicesByReimburseIds(List<Integer> reimburseIds) {
        if (reimburseIds.isEmpty()) {
            return new HashMap<>();
        }

        List<Invoice> invoices = invoiceMapper.selectList(new QueryWrapper<Invoice>()
                .in("rei_id", reimburseIds)
                .orderByAsc("rei_id", "id"));

        Map<Integer, List<Invoice>> invoiceMap = new HashMap<>();
        for (Invoice invoice : invoices) {
            invoiceMap.computeIfAbsent(invoice.getReiId(), k -> new ArrayList<>())
                    .add(invoice);
        }

        return invoiceMap;
    }


    /**
     * 构建报销明细列表
     */
    private List<ReimburseDetail> buildReimburseDetails(List<Reimburse> reimburses,
                                                        Map<Integer, List<Invoice>> invoiceMap) {
        return reimburses.stream().map(reimburse -> {
            ReimburseDetail detail = new ReimburseDetail();

            BeanUtils.copyProperties(reimburse,detail);

            // 设置该报销记录的发票信息
            detail.setInvoices(invoiceMap.getOrDefault(reimburse.getId(), new ArrayList<>()));

            return detail;
        }).collect(Collectors.toList());
    }


}
